package com.yiboshi.rehrs.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.jsoup.Connection;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.time.LocalDate;
import java.util.*;

@Slf4j
public class JsoupUtils {

    static ThreadLocal<Map<String, String>> headers = new ThreadLocal<>();

    /* public static Map<String, String> getHeadersMap(){
         Map<String, String> map = headers.get();
         if(map==null){
             headers.set(new HashMap<>());
         }
         return headers.get();
     }*/

    static ThreadLocal<Map<String, String>> cookies = new ThreadLocal<>();

    static ThreadLocal<Map<String, Object>> configMap = new ThreadLocal<>();


    public static Map<String, Object> setTimout() {
        Map<String, Object> stringObjectMap = configMap.get();
        if (stringObjectMap == null) {
            synchronized (JsoupUtils.class) {
                stringObjectMap = configMap.get();
                //f()
            }
        }
        return null;
    }

    public static Map<String, String> getHeader() {
        Map<String, String> map = headers.get();
        if (map == null) {
            map = new HashMap<>();
            headers.set(map);
        }
        if (map != null && !map.containsKey("User-Agent")) {
            map.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36");
            //map.put("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36");
        }
        return headers.get();
    }

    public static void addHeader(String key, String value) {
        if (StrUtil.isEmpty(key)) {
            return;
        }
        Map<String, String> stringStringMap = headers.get();
        if (stringStringMap == null) {
            stringStringMap = new HashMap<>();
            headers.set(stringStringMap);
        }
        if (value == null) {
            stringStringMap.remove(key);
            return;
        }
        stringStringMap.put(key, value);
    }

    public static void setCookies(Map<String, String> cookiesMap) {
        cookies.set(cookiesMap);

    }

    public static void cleanHeader() {
        headers.remove();
    }

    public static Document tryHttpGet(String url) {
        Document document = null;
        int i = 0;
        while (i++ < 2 && document == null) {
            document = httpGet(url);
            if (document != null) {
                return document;
            }
            log.error("加载失败,10s后重试,{}", url);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        return null;
    }

    public static Document httpGet2(String url) {
        HttpResponse httpResponse = HttpClientUtils.doGet(url, "", getHeader(), Collections.EMPTY_MAP);
        if (httpResponse == null) {
            //log.error("url:{},headers:{},return null",url,headers);
            return null;
        }
        //log.info("httpResponse:{}",httpResponse);
        try {
            return Jsoup.parse(httpResponse.getEntity().getContent(), null, url);
        } catch (IOException e) {
            log.error("", e);
        }
        return null;
    }

    public static Document httpGet(String url) {
        Connection connection = getConnection(url);
        try {
            //connection.proxy("127.0.0.1",8580);
            return connection.get();
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("http get error,url:{},\nheaders:{},\nmessage:{}", url, headers.get(), e.getMessage());
        } finally {
            JsoupUtils.cleanHeader();
        }
        return null;
    }

    public static Connection.Response executeGet(String url) {
        Connection connection = getConnection(url);
        try {
            //connection.proxy("127.0.0.1",8580);
            return connection.execute();
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("http get error,url:{},\nheaders:{},\nmessage:{}", url, headers.get(), e.getMessage());
        } finally {
            JsoupUtils.cleanHeader();
        }
        return null;
    }


    public static byte[] url2Bytes(String url) {
        Connection connection = getConnection(url);
        try {
            Connection.Response execute = connection.execute();
            return execute.bodyAsBytes();
        } catch (IOException e) {
            //e.printStackTrace();
            log.error("http get error,url:{},\nheaders:{},\nmessage:{}", url, headers.get(), e.getMessage());
        } finally {
            JsoupUtils.cleanHeader();
        }
        return null;
    }


    public static Connection getConnection(String url) {
        Connection connection = Jsoup.connect(url);
        connection.timeout(60000);
        connection.ignoreContentType(true);
        if (headers.get() != null) {
            connection.headers(headers.get());
        }
        if (!CollectionUtils.isEmpty(cookies.get())) {
            connection.cookies(cookies.get());
        }
        connection.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36");
        return connection;
    }

    public static Connection connect(String aurl, Map<String, String> params, Map<String, String> headers) {
        Connection connect = Jsoup.connect(aurl);
        if (headers != null && !headers.isEmpty()) {
            connect.headers(headers);
        }
        String protocolHost = AperStringUtils.getProtocolHost(aurl);
        //Accept:
        //
        //:
        //:
        //:
        //:
        //: ""
        //:
        //:
        //:
        //:
        //: 1
        connect.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
        //connect.header("Accept-Encoding", "gzip, deflate, br");
        connect.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
        connect.header("Sec-Ch-Ua", "\"Microsoft Edge\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"");
        connect.header("Sec-Ch-Ua-Mobile", "?0");
        connect.header("Cache-Control", "max-age=0");
        connect.header("Sec-Ch-Ua-Platform", "\"Windows\"");
        connect.header("Sec-Fetch-Dest", "document");
        connect.header("Sec-Fetch-Mode", "navigate");
        connect.header("Sec-Fetch-Site", "none");
        connect.header("Sec-Fetch-User", "?1");
        connect.header("Upgrade-Insecure-Requests", "1");
        connect.header("Origin", protocolHost);
        connect.header("Referer", protocolHost);
        connect.header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1");
        if (params != null && !params.isEmpty()) {
            connect.data(params);
            connect.method(Connection.Method.POST);
        } else {
            connect.method(Connection.Method.GET);
        }
        connect.ignoreContentType(true);
        if (aurl.startsWith("https")) {

        }
        connect.timeout(20000);
        return connect;
    }

    public static Connection getConnection(String url, Map<String, String> tempHeaders) {
        Connection connection = Jsoup.connect(url);
        connection.timeout(30000);
        connection.ignoreContentType(true);
        if (tempHeaders == null) {
            tempHeaders = new HashMap<>();
            tempHeaders.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36");
        }
        if (tempHeaders != null && headers.get() != null) {
            tempHeaders.putAll(headers.get());
        }
        if (!CollectionUtils.isEmpty(tempHeaders)) {
            connection.headers(tempHeaders);
        }
        boolean ua = tempHeaders.containsKey("User-Agent");
        if (!CollectionUtils.isEmpty(cookies.get())) {
            connection.cookies(cookies.get());
        }
        //if(!ua)connection.header();
        return connection;
    }

    public static JSONObject toJSON(Document doc) {
        if (doc == null) {
            log.warn("document is null");
            return new JSONObject(1);
        }
        String text = doc.body().text();
        if (!StrUtil.isEmpty(text)) {
            try {
                return JSONObject.parseObject(text);
            } catch (Exception e) {
                log.error("body to builder error,text:{}", text, e);
            }
        } else {
            log.error("body is null", text);
        }
        return new JSONObject(1);
    }

    public static JSONArray toJSONArray(Document doc) {
        if (doc == null) {
            log.warn("document is null");
            return new JSONArray(0);
        }
        String text = doc.body().text();
        if (!StrUtil.isEmpty(text)) {
            try {
                return JSONObject.parseArray(text);
            } catch (Exception e) {
                log.error("body to builder error,text:{}", text, e);
            }
        } else {
            log.error("body is null", text);
        }

        return new JSONArray(0);
    }

    public static Document post(String url, Map<String, String> headers, JSON json) {
        Connection connection = getConnection(url);
        if (!CollectionUtils.isEmpty(headers)) {
            connection.headers(headers);
        }
        //connection.com.win.fund.domain("aaa","ccc");
        connection.header("Content-Type", "application/json;charset=UTF-8");


        //connection.timeout(30000);
        connection.method(Connection.Method.POST);
        if (json != null) {
            String body = json.toJSONString();
            connection.requestBody(body);
        }
        try {
            Connection.Response res = connection.execute();
            return (res.parse());
        } catch (HttpStatusException e) {
            log.error("httpPost error,url:{} , StatusCode:{}", url, e.getStatusCode());
        } catch (IOException e) {
            log.error("httpPost error,url:{} , datas:{}", url, json, e);
        }
        return null;
    }

    public static JSONObject postJSON(String url, Map<String, String> headers, JSON json) {
        Document post = post(url, headers, json);
        return post == null ? new JSONObject() : toJSON(post);
    }

    public static Document httpPost(String url, Map<String, String> datas, String fileKey, InputStream fileInput) {
        Connection connection = getConnection(url);
        if (datas != null && !datas.isEmpty()) {
            connection.data(datas);
        }
        connection.data(fileKey, fileKey, fileInput);
        try {
            return connection.post();
        } catch (IOException e) {
            log.error("httpPost error,url:{},datas:{}", url, datas, e);
        }
        return null;
    }

    public static Document httpPost(String url, Map<String, String> headers, Map<String, String> datas) {
        Connection connection = getConnection(url);
        if (!CollectionUtils.isEmpty(headers)) {
            connection.headers(headers);
        }
        if (datas != null && !datas.isEmpty()) {
            connection.data(datas);
            connection.header("Content-Type", "application/x-www-form-urlencoded");
        }
        try {
            return connection.post();
        } catch (Exception e) {
            log.error("httpPost error,url:{},datas:{}", url, datas, e);
        }
        return null;
    }

    public static String toGetUrl(String url, Map<String, String> datas) {
        if (datas == null || datas.isEmpty()) {
            return url;
        }
        StringBuilder sn = new StringBuilder(url);
        if (!url.contains("?")) {
            sn.append("?");
        }

        Iterator<Map.Entry<String, String>> iterator = datas.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
            sn.append("&");
            sn.append(next.getKey()).append("=").append(next.getValue());
        }
        return sn.toString();
    }

    public static JSONObject httpGetJSON(String url, Map<String, String> map) {
        url = toGetUrl(url, map);
        Document document = httpGet(url);
        return toJSON(document);
    }

    public static cn.hutool.json.JSONObject httpGetJSONNew(String url, Map<String, String> map) {
        url = toGetUrl(url, map);
        Document document = httpGet(url);
        return toJSONNew(document);
    }

    public static cn.hutool.json.JSONObject toJSONNew(Document doc) {
        if (doc == null) {
            log.warn("document is null");
            return new cn.hutool.json.JSONObject(1);
        }
        String text = doc.body().text();
        if (!StrUtil.isEmpty(text)) {
            try {
                return JSONUtil.parseObj(text);
            } catch (Exception e) {
                log.error("body to builder error,text:{}", text, e);
            }
        } else {
            log.error("body is null", text);
        }
        return new cn.hutool.json.JSONObject(1);
    }


    public static JSONObject httpGetJSON(String url, Map<String, String> headers, Map<String, String> datas) {
        url = toGetUrl(url, datas);
        Connection connection = getConnection(url);
        if (!CollectionUtils.isEmpty(headers)) {
            connection.headers(headers);
        }
        Document document = null;
        try {
            document = connection.get();
            return toJSON(document);
        } catch (Exception e) {
            log.error("httpPost error,url:{},datas:{}", url, datas, e);
        }
        return null;
    }

    public static JSONObject httpPostJSON(String url, Map<String, String> headers, Map<String, String> map) {
        Document document = httpPost(url, headers, map);
        return toJSON(document);
    }


    public static Element getIndex0ByClass(Element ele, String className) {
        if (ele == null) {
            return null;
        }
        Elements elementsByClass =
                ele.getElementsByClass(className);
        if (elementsByClass.isEmpty()) {
            return null;
        }
        return elementsByClass.get(0);

    }

    public static Element selectIndex0(Element doc, String select) {
        Elements elementsByClass = doc.select(select);
        if (elementsByClass.isEmpty()) {
            return null;
        }
        return elementsByClass.get(0);
    }

    public static Element getIndex0ByAttr(Element ele, String attr) {
        if (ele == null) {
            return null;
        }
        Elements elementsByTag = ele.getElementsByAttribute(attr);
        if (elementsByTag.isEmpty()) {
            return null;
        }
        return elementsByTag.get(0);

    }

    public static Element getIndex0ByTag(Element ele, String tagName) {
        if (ele == null) {
            return null;
        }
        Elements elementsByTag = ele.getElementsByTag(tagName);
        if (elementsByTag.isEmpty()) {
            return null;
        }
        return elementsByTag.get(0);

    }

    public static Connection upload(String aurl, String fileKey, File file, Map<String, String> headers) throws FileNotFoundException {
        Connection connect = getConnection(aurl, headers);
        /*if(headers!=null&&headers.get("Content-Type")==null){
            connect.header("Content-Type","application/x-www-form-urlencoded");
        }*/
        connect.method(Connection.Method.POST);
        connect.data(fileKey, file.getAbsolutePath(), new FileInputStream(file));
        connect.ignoreContentType(true);
        connect.timeout(30000);
        return connect;
    }


    public static boolean checkUrl404(String urlStr) {
        int error = 0;
        while (error++ <= 4) {
            int urlStatusCode = getUrlStatusCode(urlStr, null);
            if (urlStatusCode >= 0) {
                return urlStatusCode == 404;
            }

        }
        return false;

    }

    public static int getUrlStatusCode(String urlStr, Map<String, String> headerMap) {
        if (StrUtil.isEmpty(urlStr)) {
            return 0;
        }
        String key = "getUrlStatusCode:" + MD5.encode(urlStr);
        Integer res = CacheUtils.getByCache10Min(key, Integer.class);
        if (res != null) {
            return res;
        }
        int i = HttpClientUtils.doHead(urlStr.trim(), null, headerMap, null);
        CacheUtils.putByCache10Min(key, i);
        return i;
    }


    public static void main2(String[] args) throws Exception {
        //String html = document.body().html();
        Map cookie = MapBuilder.start("Cookie", "existmag=mag").end();
        String aUrl = "https://www.dmmsee.lol";
        Connection connect = JsoupUtils.connect(aUrl, null, cookie);
        Connection.Response execute = connect.execute();
        Document parse = Jsoup.parse(execute.bodyStream(), null, aUrl);
        System.out.println(parse);
    }


    public static String convertShortUrl(String longUrl, LocalDate expirationDay) {

        Map data = MapBuilder.start("url", longUrl).put("is_public", "1")
                .put("active_before", DateUtils.dateToStr(expirationDay, DateUtils.SQL_DATE))
                .end();
        Map<String, String> header = MapBuilder.start("X-Goo-Api-Token", "r6RZjJksR8Lnoy4Gf9I4UHPn0z3FyD80oh9E4OP6gIs1XGSO6kqMeCFWZzqE").end();
        JSONObject jsonObject = HttpClientUtils.doJsonPost("https://goo.su/api/links/create", header, data);
        return Optional.ofNullable(jsonObject).map(o -> o.getString("short_url")).orElse(null);
    }


}
